#pragma once
#include "rtsp_client.h"
#include "websocket.h"
#include "fmp4_muxer.h"

#include <atomic>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <map>
#include <mutex>
#include <string>
#include <thread>
#include <vector>

class Rtsp2wsServer {
    class PackH2642Fmp4 {
    private:
        std::vector<u_char> vsps_;
        std::vector<u_char> vpps_;
        FMp4Info            fi_;
        bool                b_head_{false};

    public:
        FMp4Muxer fmp4muxer_;

    public:
        PackH2642Fmp4() {
            printf("PackH2642Fmp4.\n");
        }
        ~PackH2642Fmp4() {
            printf("~PackH2642Fmp4.\n");
        }

        bool PushH264Data(PayloadType pt, uint32_t time_stamp, u_int32_t nalutype,
                          std::vector<u_char>& one_nalu, std::vector<u_char>& vdata);
    };
    struct CMDConnData {
        u_int32_t      id{0};
        bool           login{false};
        std::string    request_uri;  // mount
        std::string    rtsp_uri;
        PackH2642Fmp4* pack{NULL};
    };
    enum FMP4TYPE { FTYP_MOOV, MOOF_MDAT };
    using WSServer = websocket::WSServer<Rtsp2wsServer, CMDConnData>;
    using WSConn   = WSServer::Connection;
    using Fmp4Func = std::function<void(FMP4TYPE, std::vector<u_char>)>;

private:
    WSServer          wsserver_;
    std::thread       ws_thr_;
    std::string       admincmd_help_;
    std::atomic<bool> running_;
    // map表记录rtsp信息
    std::map<std::string, std::thread> addrsr_map_;
    //记录每rtsp连接是否正常
    std::map<std::string, bool> conn_map_;
    std::mutex addrsr_map_mtx_;

    std::thread sendfmp4data_;
    // wsconn集
    int                  id_{0};  //标识每个连接额ID
    std::vector<WSConn*> vwsconn_;
    std::mutex           vwsconn_mtx_;

    // rtsp服务器，控制rtsp取流
    void AddRtsp(WSConn& conn, std::string uri);
    void RemoveRtsp(std::string uri);

    std::thread rtspcli_thr_;

    void RtspCliServerFunc(WSConn& conn, RtspClient& rtspclient, std::string uri);
    void SendFmp4DataFunc(std::string uri);

public:
    bool onWSConnect(WSConn& conn, const char* request_uri, const char* host, const char* origin,
                     const char* protocol, const char* extensions, char* resp_protocol,
                     uint32_t resp_protocol_size, char* resp_extensions,
                     uint32_t resp_extensions_size);
    void onWSClose(WSConn& conn, uint16_t status_code, const char* reason);
    void onWSMsg(WSConn& conn, uint8_t opcode, const uint8_t* payload, uint32_t pl_len);
    void onWSSegment(WSConn& conn, uint8_t opcode, const uint8_t* payload, uint32_t pl_len,
                     uint32_t pl_start_idx, bool fin);

public:
    Rtsp2wsServer(/* args */){};
    ~Rtsp2wsServer(){};

    void Start(std::string addr, u_int32_t port);
    void Stop();
};
